package com.yonyou.pmclouds.basecom.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

@Slf4j
public class HamcUtil {

	public static final String charset = "UTF-8";
	private static final String SYMBOL_AND = "&";
    private static final String SYMBOL_EQUAL = "=";
    private static final String HAMCSHA1 = "HmacSHA1";


	private static String sign(String text, String secretKey, String charset) {
		String sign = "";
		try {
			sign = signSecrt(secretKey,text);
		} catch (Exception e) {
			log.error("hmacsha1 sign:", e);
		}
		return sign;
	}

	public boolean verify(String sign, String secretKey, Map<String, String> params) {
		return verify(map2signString(params),sign, secretKey, charset);
	}

	public static String sign(String secretKey, Map<String, String> params) {
		return sign(map2signString(params), secretKey, charset);
	}

	private boolean verify(String text, String sign, String secretKey, String charset) {
		if (StringUtils.isBlank(sign)) {
			log.error("sign is emtpy");
			return false;
		}
		try {
			String computeSign = sign(text, secretKey, charset);
			if (sign.equals(computeSign)) {
				return true;
			} else {
				log.error("sign [{}] and computeSign [{}] is not match", sign, computeSign);
				return false;
			}
		} catch (Exception e) {
			log.error("hmacsha1 verify error:", e);
			return false;
		}
	}

	private static String map2signString(Map<String, String> params) {
		if (params == null || params.size() == 0) {
			return "";
		}
		List<String> keys = new ArrayList<>(params.keySet());
		Collections.sort(keys);
		StringBuilder sb = new StringBuilder();
		for (String key : keys) {
			String value = String.valueOf(params.get(key));
			if (StringUtils.isEmpty(value) || "sign".equals(value) || "Sign".equals(value) || "sign_type".equals(value)
					|| "SignType".equals(value)) {
				continue;
			}
			sb.append(key).append(SYMBOL_EQUAL).append(value).append(SYMBOL_AND);
		}
		return sb.substring(0, sb.length() - 1);
	}
	
	private static String signSecrt(String securityKey, String reqString)
			throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException {
		Mac mac = Mac.getInstance(HAMCSHA1);
		// SecretKey
        SecretKeySpec keySpec = new SecretKeySpec(securityKey.getBytes(charset), HAMCSHA1);
		mac.init(keySpec);
		mac.update(reqString.toLowerCase().getBytes(charset));

		byte[] encryptedBytes = mac.doFinal();
		return Base64.encodeBase64String(encryptedBytes);
	}

}